package com.topideal.supplychain.hades.service.impl;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.topideal.supplychain.framework.exception.BusinessException;
import com.topideal.supplychain.hades.dict.CustomfieldEnum;
import com.topideal.supplychain.hades.dict.IssueStatusEnum;
import com.topideal.supplychain.hades.dict.IssueTypeEnum;
import com.topideal.supplychain.hades.dict.MethodEnum;
import com.topideal.supplychain.hades.dto.ProjectViewDto;
import com.topideal.supplychain.hades.mapper.ProjectListMapper;
import com.topideal.supplychain.hades.service.ProjectTimeCountService;
import com.topideal.supplychain.hades.util.ExcelData;
import com.topideal.supplychain.hades.util.ExportExcelUtils;
import com.topideal.supplychain.hades.viewfilter.BasicInfoFilter;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.List;

/**
 * 项目工时统计
 *
 * @author xuxiaoyan
 * @date 2018-09-12 09:59
 */
@Service
public class ProjectTimeCountServiceImpl implements ProjectTimeCountService {

    private static Logger logger = Logger.getLogger(ProjectTimeCountServiceImpl.class);

    @Autowired
    private ProjectListMapper projectListMapper;

    /**
     * 按项目、模块维度统计工时
     *
     * @param basicInfoFilter
     * @return
     */
    @Override
    public List<ProjectViewDto> selectProjectTimeSummary(BasicInfoFilter basicInfoFilter) {
        return projectListMapper.selectProjectTimeSummary(basicInfoFilter);
    }

    /**
     * 按项目维度查询项目下jira任务及工时详情  ps(会显示直接跟项目关联的jira任务)
     *
     * @param basicInfoFilter
     * @return
     */
    @Override
    public List<ProjectViewDto> selectProjectTimeDetail(BasicInfoFilter basicInfoFilter) {
        List<ProjectViewDto> projectViewDtoList = projectListMapper.selectProjectTimeDetail(basicInfoFilter);

        if (!CollectionUtils.isEmpty(projectViewDtoList)) {
            // 项目jira任务详情填充
            fillProjectDetail(projectViewDtoList);

            // 汇总开发/测试工时
            fillTime(projectViewDtoList);

            // 将英文名联表查询查出中文名
            engNameToChinaName(projectViewDtoList);
        }

        return projectViewDtoList;
    }

    /**
     * 取中文名
     *
     * @param projectViewDtoList
     */
    private void engNameToChinaName(List<ProjectViewDto> projectViewDtoList) {
        // 报告人
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            if (StringUtils.isEmpty(projectViewDto.getReporter())) {
                continue;
            }
            projectViewDto.setReporter(selectChinaName(projectViewDto.getReporter()));
        }

        // 开发人
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            if (StringUtils.isEmpty(projectViewDto.getDeveloper())) {
                continue;
            }
            projectViewDto.setDeveloper(selectChinaName(projectViewDto.getDeveloper()));
        }

        // 测试人
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            if (StringUtils.isEmpty(projectViewDto.getTester())) {
                continue;
            }
            projectViewDto.setTester(selectChinaName(projectViewDto.getTester()));
        }
    }

    /**
     * 查询开发工时/测试工时
     *
     * @param projectViewDtoList
     */
    private void fillTime(List<ProjectViewDto> projectViewDtoList) {
        // 开发工时
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            if (!StringUtils.isEmpty(projectViewDto.getDeveloper())) {
                ProjectViewDto workLogDetail = selectWorkLogDetail(projectViewDto.getIssueId(), projectViewDto.getDeveloper());
                if (null == workLogDetail) {
                    continue;
                }
                projectViewDto.setDevelopTimeSpent(workLogDetail.getTimeWorked());
            }
        }

        // 测试工时
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            if (!StringUtils.isEmpty(projectViewDto.getTester())) {
                ProjectViewDto workLogDetail = selectWorkLogDetail(projectViewDto.getIssueId(), projectViewDto.getTester());
                if (null == workLogDetail) {
                    continue;
                }
                projectViewDto.setTestTimeSpent(workLogDetail.getTimeWorked());
            }
        }
    }

    /**
     * 填充项目详情内容：
     * 1. 将jira任务状态跟类型转化成中文
     * 2. 开发人/测试人/预计开发完成时间/预计测试完成时间等自定义字段
     * 3. 实际开发完成时间/实际测试完成时间/关闭时间 时间节点查询
     *
     * @param projectViewDtoList
     */
    private void fillProjectDetail(List<ProjectViewDto> projectViewDtoList) {

        // 将jira任务状态跟类型转化成中文
        List<BigDecimal> issueIds = Lists.newArrayList();
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            String typeName = IssueTypeEnum.getNameByValue(projectViewDto.getIssueType());
            String statusName = IssueStatusEnum.getNameByValue(projectViewDto.getIssueStatus());
            projectViewDto.setIssueType(typeName);
            projectViewDto.setIssueStatusStr(statusName);
            // 组装任务id
            issueIds.add(projectViewDto.getIssueId());
        }

        // -------自定义字段---------------------------
        // 开发人
        List<ProjectViewDto> projectDeveloperList = selectCustomfieldDetail(issueIds, CustomfieldEnum.DEVELOPER.getValue());
        setValue(projectViewDtoList, projectDeveloperList, MethodEnum.DEVELOPER.getValue(), MethodEnum.STRINGVALUE.getValue());

        // 测试人
        List<ProjectViewDto> projectTesterList = selectCustomfieldDetail(issueIds, CustomfieldEnum.TESTER.getValue());
        setValue(projectViewDtoList, projectTesterList, MethodEnum.TESTER.getValue(), MethodEnum.STRINGVALUE.getValue());

        // 预计开发时间
        List<ProjectViewDto> planDevelopList = selectCustomfieldDetail(issueIds, CustomfieldEnum.PLANDEVELOPEDTIME.getValue());
        setValue(projectViewDtoList, planDevelopList, MethodEnum.PLANDEVELOPEDTIME.getValue(), MethodEnum.DATEVALUE.getValue());

        // 预计测试时间
        List<ProjectViewDto> planTestList = selectCustomfieldDetail(issueIds, CustomfieldEnum.PLANTESTEDTIME.getValue());
        setValue(projectViewDtoList, planTestList, MethodEnum.PLANTESTEDTIME.getValue(), MethodEnum.DATEVALUE.getValue());

        // ---------------------节点时间查询-----------------------
        // 实际开发完成时间
        List<ProjectViewDto> developedTimeList = selectChangeGroupDetail(issueIds, IssueStatusEnum.DEVELOPED.getValue());
        setValue(projectViewDtoList, developedTimeList, MethodEnum.ACTUALDEVELOPEDTIME.getValue(), MethodEnum.CHANGEITEMTIME.getValue());

        // 实际测试完成时间
        List<ProjectViewDto> testedTimeList = selectChangeGroupDetail(issueIds, IssueStatusEnum.TESTED.getValue());
        setValue(projectViewDtoList, testedTimeList, MethodEnum.ACTUALTESTEDTIME.getValue(), MethodEnum.CHANGEITEMTIME.getValue());

        // 关闭时间
        List<ProjectViewDto> closeTimeList = selectChangeGroupDetail(issueIds, IssueStatusEnum.CLOSE.getValue());
        setValue(projectViewDtoList, closeTimeList, MethodEnum.CLOSETIME.getValue(), MethodEnum.CHANGEITEMTIME.getValue());

        // 统一时间显示格式
        formatTimeStr(projectViewDtoList);
    }

    /**
     * YY
     * 统一时间显示格式：yyyy-MM-dd HH:mm:ss
     *
     * @param projectViewDtoList
     */
    private void formatTimeStr(List<ProjectViewDto> projectViewDtoList) {
        String planDevelopedTime;
        String planTestedTime;
        String actualDevelopedTime;
        String actualTestedTime;
        String closeTime;
        String issueCreateTime;
        for (ProjectViewDto projectViewDto : projectViewDtoList) {
            planDevelopedTime = projectViewDto.getPlanDevelopedTime();
            planTestedTime = projectViewDto.getPlanTestedTime();
            actualDevelopedTime = projectViewDto.getActualDevelopedTime();
            actualTestedTime = projectViewDto.getActualTestedTime();
            closeTime = projectViewDto.getCloseTime();
            issueCreateTime = projectViewDto.getIssueCreateTime();

            if (!StringUtils.isEmpty(planDevelopedTime)) {
                projectViewDto.setPlanDevelopedTime(planDevelopedTime.substring(0, planDevelopedTime.length() - 2));
            }
            if (!StringUtils.isEmpty(planTestedTime)) {
                projectViewDto.setPlanTestedTime(planTestedTime.substring(0, planTestedTime.length() - 2));
            }
            if (!StringUtils.isEmpty(actualDevelopedTime)) {
                projectViewDto.setActualDevelopedTime(actualDevelopedTime.substring(0, actualDevelopedTime.length() - 2));
            }
            if (!StringUtils.isEmpty(actualTestedTime)) {
                projectViewDto.setActualTestedTime(actualTestedTime.substring(0, actualTestedTime.length() - 2));
            }
            if (!StringUtils.isEmpty(closeTime)) {
                projectViewDto.setCloseTime(closeTime.substring(0, closeTime.length() - 2));
            }
            if (!StringUtils.isEmpty(issueCreateTime)) {
                projectViewDto.setIssueCreateTime(issueCreateTime.substring(0, issueCreateTime.length() - 2));
            }
        }
    }

    /**
     * 批量匹配共有方法
     *
     * @param projectViewDtoList
     * @param sourceList
     * @param setMethodStr
     * @param getMethodStr
     */
    private void setValue(List<ProjectViewDto> projectViewDtoList, List<ProjectViewDto> sourceList, String setMethodStr, String getMethodStr) {
        if (!CollectionUtils.isEmpty(sourceList)) {
            ImmutableMap<BigDecimal, ProjectViewDto> issueIdToSourceMap = Maps.uniqueIndex(sourceList, new Function<ProjectViewDto, BigDecimal>() {
                @Override
                public BigDecimal apply(ProjectViewDto source) {
                    return source.getIssueId();
                }
            });
            Class projectViewDtoClazz = ProjectViewDto.class;
            Method getMethod;
            Method setMethod;
            ProjectViewDto source;
            try {
                getMethod = projectViewDtoClazz.getMethod("get" + getMethodStr);
                setMethod = projectViewDtoClazz.getMethod("set" + setMethodStr, String.class);
                for (ProjectViewDto projectViewDto : projectViewDtoList) {
                    source = issueIdToSourceMap.get(projectViewDto.getIssueId());
                    if (null == source) {
                        continue;
                    }
                    setMethod.invoke(projectViewDto, (String) getMethod.invoke(source));
                }
            } catch (Exception e) {
                logger.error("项目详情批量匹配出错！", e);
                throw new BusinessException("项目详情批量匹配出错！");
            }
        }
    }


    /**
     * 批量查询自定义字段信息
     *
     * @param issueIds
     * @param customfieldId
     * @return
     */
    @Override
    public List<ProjectViewDto> selectCustomfieldDetail(List<BigDecimal> issueIds, String customfieldId) {
        return projectListMapper.selectCustomfieldDetail(issueIds, customfieldId);
    }

    /**
     * 批量查询时间节点信息（实际开发完成时间/实际测试完成时间/关闭时间）
     *
     * @param issueIds
     * @param issueStatus
     * @return
     */
    @Override
    public List<ProjectViewDto> selectChangeGroupDetail(List<BigDecimal> issueIds, String issueStatus) {
        return projectListMapper.selectChangeGroupDetail(issueIds, issueStatus);
    }

    /**
     * 查询任务的开发/测试登记工时
     *
     * @param issueId
     * @param author
     * @return
     */
    @Override
    public ProjectViewDto selectWorkLogDetail(BigDecimal issueId, String author) {
        return projectListMapper.selectWorkLogDetail(issueId, author);
    }

    /**
     * 查找中文名
     *
     * @param userKey
     * @return
     */
    @Override
    public String selectChinaName(String userKey) {
        return projectListMapper.selectChinaName(userKey);
    }

    /**
     * 按模块维度查询jira任务及工时详情
     *
     * @param filter
     * @return
     */
    @Override
    public List<ProjectViewDto> selectComponentTimeDetail(BasicInfoFilter filter) {
        List<ProjectViewDto> projectViewDtos = projectListMapper.selectComponentTimeDetail(filter);
        if (!CollectionUtils.isEmpty(projectViewDtos)) {
            // 模块jira任务详情填充
            fillProjectDetail(projectViewDtos);

            // 汇总开发/测试工时
            fillTime(projectViewDtos);

            // 将英文名联表查询查出中文名
            engNameToChinaName(projectViewDtos);
        }
        return projectViewDtos;
    }

    /**
     * 导出项目模块工时统计列表
     *
     * @param basicInfoFilter
     * @param response
     */
    @Override
    public void exportProjectListExcel(BasicInfoFilter basicInfoFilter, HttpServletResponse response) throws IOException {
        List<ProjectViewDto> projectViewDtos = selectProjectTimeSummary(basicInfoFilter);

        if (CollectionUtils.isEmpty(projectViewDtos)) {
            throw new BusinessException("没有数据！");
        }
        if (projectViewDtos.size() > 5000) {
            throw new BusinessException("导出条数超过5000，请修改查询条件或联系管理员处理");
        }

        ExcelData data = new ExcelData();
        data.setName("项目模块工时统计列表");
        List<String> titles = Lists.newArrayList();
        titles.add("项目");
        titles.add("模块");
        titles.add("总工时（小时）");
        data.setTitles(titles);

        List<List<Object>> rows = Lists.newArrayList();
        for (ProjectViewDto projectViewDto : projectViewDtos) {
            List<Object> row = Lists.newArrayList();
            row.add(projectViewDto.getPName());
            row.add(projectViewDto.getCName());
            row.add(projectViewDto.getPTotalTimeSpent());
            rows.add(row);
        }
        data.setRows(rows);
        ExportExcelUtils.exportExcel(response, "projectTimeSummary.xlsx", data);
    }


    /**
     * 项目工时详情导出
     *
     * @param filter
     * @param response
     * @throws Exception
     */
    @Override
    public void exportProjectDetailExcel(BasicInfoFilter filter, HttpServletResponse response) throws IOException {
        List<ProjectViewDto> projectViewDtos = projectListMapper.selectProjectTimeDetail(filter);

        if (CollectionUtils.isEmpty(projectViewDtos)) {
            throw new BusinessException("没有数据！");
        }
        if (projectViewDtos.size() > 200) {
            throw new BusinessException("导出条数超过200，请修改查询条件或联系管理员处理");
        }

        // 项目jira任务详情填充
        fillProjectDetail(projectViewDtos);

        // 汇总开发/测试工时
        fillTime(projectViewDtos);

        // 将英文名联表查询查出中文名
        engNameToChinaName(projectViewDtos);

        ExcelData data = new ExcelData();
        data.setName("项目工时详情统计列表");
        List<String> titles = Lists.newArrayList();
        titles.add("编号");
        titles.add("项目");
        titles.add("模块");
        titles.add("标题");
        titles.add("任务类型");
        titles.add("状态");
        titles.add("创建时间");
        titles.add("报告人");
        titles.add("开发人");
        titles.add("测试人");
        titles.add("预计开发完成时间");
        titles.add("实际开发完成时间");
        titles.add("预计测试完成时间");
        titles.add("实际测试完成时间");
        titles.add("关闭时间");
        titles.add("开发工时（小时）");
        titles.add("测试工时（小时）");
        titles.add("总工时（小时）");

        data.setTitles(titles);

        List<List<Object>> rows = Lists.newArrayList();
        for (ProjectViewDto projectViewDto : projectViewDtos) {
            List<Object> row = Lists.newArrayList();
            row.add(projectViewDto.getJiraNum());
            row.add(projectViewDto.getPName());
            row.add(projectViewDto.getCName());
            row.add(projectViewDto.getTitle());
            row.add(projectViewDto.getIssueType());
            row.add(projectViewDto.getIssueStatusStr());
            row.add(projectViewDto.getIssueCreateTime());
            row.add(projectViewDto.getReporter());
            row.add(projectViewDto.getDeveloper());
            row.add(projectViewDto.getTester());
            row.add(projectViewDto.getPlanDevelopedTime());
            row.add(projectViewDto.getActualDevelopedTime());
            row.add(projectViewDto.getPlanTestedTime());
            row.add(projectViewDto.getActualTestedTime());
            row.add(projectViewDto.getCloseTime());
            row.add(projectViewDto.getDevelopTimeSpent());
            row.add(projectViewDto.getTestTimeSpent());
            row.add(projectViewDto.getITotalTimeSpent());

            rows.add(row);
        }
        data.setRows(rows);
        ExportExcelUtils.exportExcel(response, "projectTimeDetail.xlsx", data);
    }

    /**
     * 模块工时详情导出
     *
     * @param filter
     * @param response
     */
    @Override
    public void exportComponentDetailExcel(BasicInfoFilter filter, HttpServletResponse response) throws IOException {
        List<ProjectViewDto> projectViewDtos = projectListMapper.selectComponentTimeDetail(filter);

        if (CollectionUtils.isEmpty(projectViewDtos)) {
            throw new BusinessException("没有数据！");
        }
        if (projectViewDtos.size() > 200) {
            throw new BusinessException("导出条数超过200，请修改查询条件或联系管理员处理");
        }

        // 项目jira任务详情填充
        fillProjectDetail(projectViewDtos);

        // 汇总开发/测试工时
        fillTime(projectViewDtos);

        // 将英文名联表查询查出中文名
        engNameToChinaName(projectViewDtos);

        ExcelData data = new ExcelData();
        data.setName("模块工时详情统计列表");
        List<String> titles = Lists.newArrayList();
        titles.add("编号");
        titles.add("模块");
        titles.add("项目");
        titles.add("标题");
        titles.add("任务类型");
        titles.add("状态");
        titles.add("创建时间");
        titles.add("报告人");
        titles.add("开发人");
        titles.add("测试人");
        titles.add("预计开发完成时间");
        titles.add("实际开发完成时间");
        titles.add("预计测试完成时间");
        titles.add("实际测试完成时间");
        titles.add("关闭时间");
        titles.add("开发工时（小时）");
        titles.add("测试工时（小时）");
        titles.add("总工时（小时）");

        data.setTitles(titles);

        List<List<Object>> rows = Lists.newArrayList();
        for (ProjectViewDto projectViewDto : projectViewDtos) {
            List<Object> row = Lists.newArrayList();
            row.add(projectViewDto.getJiraNum());
            row.add(projectViewDto.getCName());
            row.add(projectViewDto.getPName());
            row.add(projectViewDto.getTitle());
            row.add(projectViewDto.getIssueType());
            row.add(projectViewDto.getIssueStatusStr());
            row.add(projectViewDto.getIssueCreateTime());
            row.add(projectViewDto.getReporter());
            row.add(projectViewDto.getDeveloper());
            row.add(projectViewDto.getTester());
            row.add(projectViewDto.getPlanDevelopedTime());
            row.add(projectViewDto.getActualDevelopedTime());
            row.add(projectViewDto.getPlanTestedTime());
            row.add(projectViewDto.getActualTestedTime());
            row.add(projectViewDto.getCloseTime());
            row.add(projectViewDto.getDevelopTimeSpent());
            row.add(projectViewDto.getTestTimeSpent());
            row.add(projectViewDto.getITotalTimeSpent());

            rows.add(row);
        }
        data.setRows(rows);
        ExportExcelUtils.exportExcel(response, "componentTimeDetail.xlsx", data);
    }

    /**
     * 项目详情导出条数check
     *
     * @param filter
     */
    @Override
    public void isExportProjectDetailExcel(BasicInfoFilter filter) {
        List<ProjectViewDto> projectViewDtos = projectListMapper.selectProjectTimeDetail(filter);

        if (CollectionUtils.isEmpty(projectViewDtos)) {
            throw new BusinessException("没有数据！");
        }
        if (projectViewDtos.size() > 200) {
            throw new BusinessException("导出条数超过200，请修改查询条件或联系管理员处理");
        }
    }

}
